/**
 * @author		Ben Layet
 * @version 	1.0
 * @date		25 Sep 2008
 */
package org.ignoramus.application.store;

import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.ignoramus.application.model.StudyEvent;
import org.ignoramus.application.model.StudyEventsLog;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * The XML Template data parser.
 */
public class LogParser
{
	/** Format for EDT Time */
	static final DateFormat		gmt_format		= new SimpleDateFormat("dd/MM/yyyy HH:mm:ss zzz");

	/** card tag. */
	static final String			card_tag		= "card";
	/** event tag. */
	static final String			event_tag		= "event";
	/** date attribute. */
	static final String			date_attribute	= "date";
	/** type attribute. */
	static final String			type_attribute	= "type";
	/** id attribute. */
	static final String			id_attribute	= "id";

	/** The input stream data. */
	private final InputStream	data;

	/** The logs. */
	private Map<String, StudyEventsLog>		logs				= null;

	/**
	 * Constructs with the input stream data.
	 * 
	 * @param data
	 *            the input stream data.
	 */
	public LogParser(InputStream data)
	{
		this.data = data;
	}

	/**
	 * parses the file.
	 * 
	 * @throws StoreException
	 *             if the file cannot be parsed.
	 */
	private void parse() throws StoreException
	{
		// check if it has already been parsed
		if (logs == null)
		{
			//create the log
			logs = new HashMap<String, StudyEventsLog>();
			
			// document builder factory
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			try
			{
				// document builder
				DocumentBuilder db = dbf.newDocumentBuilder();
				// parse the document
				Document doc = db.parse(data);
				// normalise the document
				doc.getDocumentElement().normalize();

				// get the cards
				NodeList cardElemNodes = doc.getElementsByTagName(card_tag);
				// loop through the card nodes
				for (int i = 0; i < cardElemNodes.getLength(); i++)
				{
					//create the card log
					StudyEventsLog log = new StudyEventsLog();
					
					// get the next card element
					Element cardElement = (Element) cardElemNodes.item(i);
					// get the card id
					String cardId = cardElement.getAttribute(id_attribute);

					//add the card and its log
					logs.put(cardId, log);
					
					// get the events
					NodeList eventElemNodes = cardElement.getElementsByTagName(event_tag);
					// loop through the card nodes
					for (int j = 0; j < eventElemNodes.getLength(); j++)
					{
						// get the next event element
						Element eventElement = (Element) eventElemNodes.item(j);
						// get the date
						String dateString = eventElement.getAttribute(date_attribute);
						// get the test
						String eventString = eventElement.getAttribute(type_attribute);

						//create the date
						Date date = gmt_format.parse(dateString);
						//create the date
						StudyEvent event = StudyEvent.valueOf(eventString);

						//add the event to the log	
						log.put(date, event);
					}

				}

				// close the input stream
				data.close();

			}
			catch (ParserConfigurationException e)
			{
				throw new StoreException("Cannot parse the log file.", e);
			}
			catch (SAXException e)
			{
				throw new StoreException("Cannot parse the log file.", e);
			}
			catch (IOException e)
			{
				throw new StoreException("Cannot parse the log file.", e);
			}
			catch (ParseException e)
			{
				throw new StoreException("Cannot parse the log file.", e);
			}
		}
	}

	/**
	 * @returns the logs.
	 * @throws StoreException
	 *             if the file cannot be parsed.
	 */
	public Map<String, StudyEventsLog> getLogs() throws StoreException
	{
		parse();
		return logs;
	}

}
